﻿/**
 * @file deque_ie2.c
 * Copyright (c) 2021 Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2021-06-02
 * @version : 1.0.0.0
 * @brief   : 对 双端队列 容器的数据进行 插入/删除 操作。
 */

/**
 * The MIT License (MIT)
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "std_deque.h"
#include "std_mdebug.h"
#include <stdio.h>
#include <memory.h>

////////////////////////////////////////////////////////////////////////////////

#define XUNAME_LEN  64

/**
 * @struct user_t
 * @brief  用于测试的 自定义结构体数据。
 */
typedef struct user_t
{
    xstd_int32_t xit_uid;
    xstd_char_t  xszt_uname[XUNAME_LEN];
} user_t;

/**********************************************************/
/**
 * @brief 节点存储的元素对象 的 拷贝构造操作 的回调函数类型。
 * 
 * @param [out] xet_dptr : 目标存储的元素对象。
 * @param [in ] xet_sptr : 源数据的元素对象。
 * @param [in ] xet_ctxt : 节点元素的上下文信息。
 */
xstd_void_t user_copyctor(
                xstd_elem_t xet_dptr,
                xstd_elem_t xet_sptr,
                xstd_ctxt_t xet_ctxt)
{
    ((user_t *)xet_dptr)->xit_uid = ((user_t *)xet_sptr)->xit_uid;
    memcpy(
        ((user_t *)xet_dptr)->xszt_uname,
        ((user_t *)xet_sptr)->xszt_uname,
        XUNAME_LEN * sizeof(xstd_char_t));
}

/**********************************************************/
/**
 * @brief 节点存储的元素对象 的 拷贝构造操作 的回调函数类型。
 * 
 * @param [out] xet_dptr : 目标存储的元素对象。
 * @param [in ] xet_sptr : 源数据的元素对象。
 * @param [in ] xet_ctxt : 节点元素的上下文信息。
 */
xstd_void_t user_copymove(
                xstd_elem_t xet_dptr,
                xstd_elem_t xet_sptr,
                xstd_ctxt_t xet_ctxt)
{
    ((user_t *)xet_dptr)->xit_uid = ((user_t *)xet_sptr)->xit_uid;
    memcpy(
        ((user_t *)xet_dptr)->xszt_uname,
        ((user_t *)xet_sptr)->xszt_uname,
        XUNAME_LEN * sizeof(xstd_char_t));

    ((user_t *)xet_sptr)->xit_uid = 0;
    memset(((user_t *)xet_sptr)->xszt_uname, 0, XUNAME_LEN * sizeof(xstd_char_t));
}

/**********************************************************/
/**
 * @brief 创建 user_t 类型的双端队列容器对象。
 */
xdeq_this_t user_deque_create(void)
{
    static xstd_allocator_t user_altor = { XSTD_NULL };
    xstd_context_t user_ctxt  = { 0 };

    if (XSTD_NULL == user_altor.xfunc_allocate)
    {
        user_altor.xfunc_allocate = xstd_altor_comm.xfunc_allocate;
        user_altor.xfunc_dealloc  = xstd_altor_comm.xfunc_dealloc ;
        user_altor.xfunc_copyfrom = &user_copyctor;
        user_altor.xfunc_copymove = &user_copymove;
        user_altor.xfunc_destruct = xstd_altor_comm.xfunc_destruct;
    }

    user_ctxt.xstd_etype = XSTD_ETYPE_USER + 0x00000001;
    user_ctxt.xstd_esize = sizeof(user_t);
    user_ctxt.xstd_owner = XDEQ_NULL;
    user_ctxt.xstd_altor = &user_altor;

    return std_deque_create(&user_ctxt);
}

/**********************************************************/
/**
 * @brief 打印输出（user_t 类型）双端队列容器对象的 各个节点信息。
 */
xstd_void_t user_deque_print(xdeq_this_t xdeq_user)
{
    xstd_size_t xst_count = 0;
    xdeq_iter_t xdeq_iter = std_deque_begin(xdeq_user);
    xdeq_iter_t xdeq_vend = std_deque_end(xdeq_user);

    user_t * xuser_ptr = XSTD_NULL;

    if (std_deque_size(xdeq_user) <= 0)
    {
        printf("user_deque(0) \n");
        return;
    }

    printf("user_deque(%d) [[[\n", (xstd_int32_t)std_deque_size(xdeq_user));

    for (xst_count  = 0;
         xdeq_iter != xdeq_vend;
         xdeq_iter  = std_deque_next(xdeq_user, xdeq_iter))
    {
        xuser_ptr = (user_t *)std_deque_elem(xdeq_user, xdeq_iter);

        printf("%2d. (%d, %s)\n",
            (xstd_int32_t)xst_count,
            xuser_ptr->xit_uid,
            xuser_ptr->xszt_uname);

        if (++xst_count == std_deque_size(xdeq_user))
        {
            printf("]]] user_deque\n\n");
        }
    }
}

////////////////////////////////////////////////////////////////////////////////

/**********************************************************/
/**
 * @brief 测试程序的 main 入口函数。
 */
int main(int argc, char * argv[])
{
    xmdb_this_t xmdb_comm = XSTD_NULL;

    xstd_int32_t  xit_iter  = 0;
    xstd_int32_t  xit_count = 128;
    user_t        user_info;
    xdeq_this_t xdeq_user = XSTD_NULL;

    //======================================

    xmdb_comm = (xmdb_this_t)std_mdbcomm_start();
    printf("%d. mem count : %d, sizeof(xstd_deque_t) = %d\n",
           __LINE__,
           (xstd_int32_t)std_mdbcomm_count(),
           (xstd_int32_t)std_deque_sizeof());

    //======================================
    // initial

    printf("initial: \n");

    xdeq_user = user_deque_create();
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // insert begin

    printf("insert begin: \n");

    user_info.xit_uid = 0;
    snprintf(user_info.xszt_uname, XUNAME_LEN, "uname[%d]", __LINE__);
    std_deque_insert(xdeq_user, std_deque_begin(xdeq_user), &user_info);
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // insert end

    printf("insert end: \n");

    user_info.xit_uid = 1;
    snprintf(user_info.xszt_uname, XUNAME_LEN, "uname[%d]", __LINE__);
    std_deque_insert(xdeq_user, std_deque_end(xdeq_user), &user_info);
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // insert rbegin

    printf("insert rbegin: \n");

    user_info.xit_uid = 2;
    snprintf(user_info.xszt_uname, XUNAME_LEN, "uname[%d]", __LINE__);
    std_deque_insert_n(xdeq_user, std_deque_rbegin(xdeq_user), 3, &user_info);
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // insert head

    printf("insert head: \n");

    user_info.xit_uid = 3;
    snprintf(user_info.xszt_uname, XUNAME_LEN, "uname[%d]", __LINE__);
    std_deque_insert_n(xdeq_user, std_deque_iter(xdeq_user, 1), 10, &user_info);
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // insert tail

    printf("insert tail: \n");

    user_info.xit_uid = 4;
    snprintf(user_info.xszt_uname, XUNAME_LEN, "uname[%d]", __LINE__);
    std_deque_insert_n(xdeq_user, std_deque_iter(xdeq_user, std_deque_size(xdeq_user) - 2), 7, &user_info);
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // erase begin

    printf("erase begin: \n");

    std_deque_erase(xdeq_user, std_deque_begin(xdeq_user));
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // erase head

    printf("erase head: \n");

    std_deque_erase(xdeq_user, std_deque_iter(xdeq_user, 1));
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // erase head

    printf("erase head 2: \n");

    std_deque_erase_range(xdeq_user, std_deque_iter(xdeq_user, 1), std_deque_iter(xdeq_user, 4));
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // erase rbegin

    printf("erase rbegin: \n");

    std_deque_erase(xdeq_user, std_deque_rbegin(xdeq_user));
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // erase tail

    printf("erase tail: \n");

    std_deque_erase_range(
        xdeq_user,
        std_deque_iter(xdeq_user, std_deque_size(xdeq_user) - 6),
        std_deque_iter(xdeq_user, std_deque_size(xdeq_user) - 3));
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // erase range

    printf("erase range: \n");

    std_deque_erase_range(
        xdeq_user,
        std_deque_iter(xdeq_user, 1),
        std_deque_iter(xdeq_user, std_deque_size(xdeq_user) - 1));
    user_deque_print(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================
    // clear

    printf("clear: \n");

    std_deque_clear(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());

    //======================================

    std_deque_destroy(xdeq_user);

    printf("%d. mem count : %d\n\n", __LINE__, (xstd_int32_t)std_mdbcomm_count());
    std_mdbcomm_stop();

    //======================================

    return 0;
}

/////////////////////////////////////////////////////////////////////////////////

